
package it.jaco.aswiimotelib {

	import flash.errors.*;
	import flash.events.*;
	import flash.net.*;
	import flash.utils.*;

	import it.jaco.aswiimotelib.events.*;

	public class WiimoteSocket extends Socket {

		public static const LED1:uint = 0x01;
		public static const LED2:uint = 0x02;
		public static const LED3:uint = 0x04;
		public static const LED4:uint = 0x08;

		public static const CMD_REQUEST_TOGGLE_LEDS:uint = 0x35;
		public static const CMD_REQUEST_TOGGLE_SINGLE_LED:uint = 0x36;
		public static const CMD_REQUEST_TOGGLE_RUMBLE:uint = 0x40;
		public static const CMD_GET_ACCEL_MAX_RANGE:uint = 0x50;
		public static const CMD_GET_IR_MAX_SIZE:uint = 0x60;
		public static const CMD_REQUEST_STATUS:uint = 0x70;

		private var cmds:Object;
		
	    public function WiimoteSocket() {
        
	        cmds = new Object();
	        cmds.a = "dispatch_wm_accelerometer";
	        cmds.b = "dispatch_wm_buttons";
	        cmds.i = "dispatch_wm_irwebcam";
	        
	        cmds.na = "dispatch_nc_accelerometer";
	        cmds.nb = "dispatch_nc_buttons";
	        cmds.ns = "dispatch_nc_stick";
	        
	        cmds.ws = "dispatch_wmStatus";
	        
	        addEventListener(Event.CLOSE, closeHandler);
	        addEventListener(Event.CONNECT, connectHandler);
	        addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
	        addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
	        addEventListener(ProgressEvent.SOCKET_DATA, onWiimoteSignal);
	    }

	    private function closeHandler(event:Event):void {
	        //trace("closeHandler: " + event);
	    }

	    private function connectHandler(event:Event):void {
	        //trace("connectHandler: " + event);
	    	request_status();
	    }

	    private function ioErrorHandler(event:IOErrorEvent):void {
	        //trace("ioErrorHandler: " + event);
	    }

	    private function securityErrorHandler(event:SecurityErrorEvent):void {
	        //trace("securityErrorHandler: " + event);
	    }

	    private function onWiimoteSignal(evt:ProgressEvent):void {
	        var str:String = readUTFBytes(bytesAvailable);
	    	//trace(str);
	    	var cmdAr:Array = str.split(":");
	    	var cmd:String = cmdAr[0];
	    

			var args:String = cmdAr[1].replace(", ", ",");
	    	//trace("args: " +args);
	    	//trace(cmd);
    		if(cmd == "ws") trace("dispatching: " + args);
	    	this[cmds[cmd]](args);
	    }

	    private function dispatch_wm_accelerometer(args:String):void {
			var accel:Array = args.split(",");
			var accelVO:AccelVO = new AccelVO();
			accelVO.accelX = parseInt(accel[0]);
			accelVO.accelY = parseInt(accel[1]);
			accelVO.accelZ = parseInt(accel[2]);

			var wmae:WiimoteAccelEvent = new WiimoteAccelEvent(WiimoteAccelEvent.ACCELEROMETER_CHANGE);
			wmae.data = accelVO;
			dispatchEvent(wmae);
	    }

	    private function dispatch_wm_buttons(args:String):void {

	    	var evts:Array = new Array();

		    for(var i:int = 0 ; i < 11; i++){
		    	var stateStr:String = "";
	    		var state:uint = parseInt(args.charAt(i));
	    		var evtName:String = WiimoteButtonsEvent.get_buttonNameByIndex(i);
		    
	    		if(state == WiimoteButtonsEvent.CHANGE_DOWN) stateStr = "Down";
	    		else if(state == WiimoteButtonsEvent.CHANGE_UP) stateStr = "Click";
	    		
	    		if(stateStr.length) evts.push(evtName + stateStr)
    		}

    		if(args.charAt(11) == "_") evts.push(WiimoteButtonsEvent.BUTTONS_UP);
    		
    		for each(var e:String in evts) {
			    dispatchEvent(new WiimoteButtonsEvent(e));
				trace(e);
    		}
	    }

	    private function dispatch_wm_irwebcam(args:String):void {
			var irs:Array = args.split("|");
			var weData:Array = new Array();
			for(var j:int = 0; j < 4; j++){
				var irVO:IrVO = new IrVO();

				if(irs[j].charAt(0) == "1"){
					var irsAr:Array = irs[j].split(",");
					irVO.valid = true;
					irVO.x = parseInt(irsAr[2]);
					irVO.y = parseInt(irsAr[3]);
					irVO.size = parseInt(irsAr[4]);
				}

				weData.push(irVO);
			}

			var wmie:WiimoteIrEvent = new WiimoteIrEvent(WiimoteIrEvent.IR_CHANGE);
			wmie.data = weData;
			dispatchEvent(wmie);
	    }
	    
	    private function dispatch_wmStatus(args:String):void {
	    	trace("dispatch_wmStatus: " +args);
	    	var sAr:Array = args.split(",");
	    	var wmbe:WiimoteStatusEvent = new WiimoteStatusEvent(WiimoteStatusEvent.WIIMOTE_STATUS);
	    	var wmData:StatusVO = new StatusVO();
	    	wmData.battery = parseInt(sAr[0]);
	    	wmData.ext_type = parseInt(sAr[1]);
	    	wmData.led = parseInt(sAr[2]);
	    	wmData.rumble = parseInt(sAr[3]) > 0 ? true : false;
	    	wmbe.data = wmData;
	    	dispatchEvent(wmbe);
	    }
	    
	    private function dispatch_nc_accelerometer(args:String):void {
			var accel:Array = args.split(",");
			var accelVO:AccelVO = new AccelVO();
			accelVO.accelX = parseInt(accel[0]);
			accelVO.accelY = parseInt(accel[1]);
			accelVO.accelZ = parseInt(accel[2]);
	
			var ncae:NunchukAccelEvent = new NunchukAccelEvent(NunchukAccelEvent.ACCELEROMETER_CHANGE);
			ncae.data = accelVO;
			dispatchEvent(ncae);
	    }

	    private function dispatch_nc_buttons(args:String):void {

	    	var evts:Array = new Array();

		    for(var i:int = 0 ; i < 2; i++){
		    	var stateStr:String = "";
	    		var state:uint = parseInt(args.charAt(i));
	    		var evtName:String = NunchukButtonsEvent.get_buttonNameByIndex(i);
		    
	    		if(state == NunchukButtonsEvent.CHANGE_DOWN) stateStr = "Down";
	    		else if(state == NunchukButtonsEvent.CHANGE_UP) stateStr = "Click";
	    		
	    		if(stateStr.length) evts.push(evtName + stateStr)
			}
	
			if(args.charAt(2) == "_") evts.push(NunchukButtonsEvent.BUTTONS_UP);
			
			for each(var e:String in evts) {
			    dispatchEvent(new NunchukButtonsEvent(e));
				trace(e);
			}
	    }

	    private function dispatch_nc_stick(args:String):void {
			var stick:Array = args.split(",");
	    	var stickVO:StickVO = new StickVO();
	    	stickVO.x = parseInt(stick[0]);
	    	stickVO.y = parseInt(stick[1]);
	    	var ncse:NunchukStickEvent = new NunchukStickEvent(NunchukStickEvent.STICK_CHANGE);
	    	ncse.data = stickVO;
	    	
			dispatchEvent(ncse);
	    }
	    
	    private function send_command(cmd:ByteArray):void {

	    	cmd.position = 0;
	    	var str:String = "c" + cmd.readUTFBytes(cmd.length);
	    	trace("cmd length: " +cmd.length);
	    	trace("sending: " +str);

	        try {
	            writeUTFBytes(str);
	        }
	        catch(e:IOError) {
	            trace(e);
	        }
	    }
	    
	    public function wm_connect(host:String = "127.0.0.1", port:uint = 32768):void{
	        super.connect(host, port);
	    }

	    public function set_rumble(rumbleStatus:Boolean):void {
	    	var cmd:ByteArray = new ByteArray();
	    	cmd.writeByte(CMD_REQUEST_TOGGLE_RUMBLE);
	    	if(rumbleStatus) cmd.writeByte(0x31);
	    	else cmd.writeByte(0x30);

	    	send_command(cmd);
	    }
	    

	    /**
	     *
	     */
	    public function set_led(ledNumber:uint, ledStatus:Boolean):void {
	    	var cmd:ByteArray = new ByteArray();
	    	cmd.writeByte(CMD_REQUEST_TOGGLE_SINGLE_LED);
	    	cmd.writeByte(ledNumber | 0x30);
	    	if(ledStatus) cmd.writeByte(0x31);
	    	else cmd.writeByte(0x30);

	    	send_command(cmd);
	    }

	    public function set_leds(ledsStatus:uint, reverseOrder:Boolean = false):void {

	    	var cmd:ByteArray = new ByteArray();
	    	cmd.writeByte(CMD_REQUEST_TOGGLE_LEDS);

	    	var ro:uint = 0;
	    	
	    	if(reverseOrder){
	    		ro |= (ledsStatus & 0x08) >> 3;
	    		ro |= (ledsStatus & 0x04) >> 1;
	    		ro |= (ledsStatus & 0x02) << 1;
	    		ro |= (ledsStatus & 0x01) << 3;
	    	}
	    	else ro = ledsStatus;

	    	cmd.writeByte(ro | 0x30);
	    	send_command(cmd);
	    }

	    public function request_status():void {
	    	var cmd:ByteArray = new ByteArray();
	    	cmd.writeByte(CMD_REQUEST_STATUS);
	    	cmd.writeUTFBytes("0000000000000000");
	    	cmd.position = 0;

	    	send_command(cmd);
	    }
	}
}